//
//  util.h
//  GCDBenchmark
//
//  Created by 郭晓龙 on 2025/10/9.
//

#ifndef util_h
#define util_h

#include <chrono>
#include <thread>
#include <random>
#include <mach/mach_time.h>

#include <os/signpost.h>
#include <os/log.h>

#ifdef __cplusplus
extern "C" {
#endif

// 声明全局 log 获取函数（实现在 trace.m 中）
os_log_t get_perf_log(void);

#ifdef __cplusplus
}
#endif

// Event signpost - 单点事件
#define TRACE_COUNT(name, expr) do { \
    os_log_t _log = get_perf_log(); \
    os_signpost_id_t _spid = os_signpost_id_generate(_log); \
    os_signpost_event_emit(_log, _spid, name, "%s=%llu", name, (unsigned long long)(expr)); \
} while (0)

static int cycles_per_us = 0;

inline void get_cycles_per_us()
{
    if (cycles_per_us == 0) {
        auto start = std::chrono::steady_clock::now();
        volatile long sum = 0;
        for (int i = 0; i < 50000000; i++) sum += i;
        auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - start).count();
        cycles_per_us = 50000000 / elapsed;
    }
}

// returns ns for diff
inline uint64_t arm64_cnt_vct()
{
    return clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
}

inline void cpu_intensive_task(size_t duration_us) {
    // 执行固定计算量，不检查时间
    volatile long sum = 0;
    for (long i = 0; i < cycles_per_us * duration_us; i++) {
        sum += (i * i) ^ (i >> 1);
    }
}

inline void io_intensive_task(size_t us)
{
    std::this_thread::sleep_for(std::chrono::microseconds(us));
}

inline void cpu_suspend_task(size_t us) {
    uint64_t tsc = arm64_cnt_vct();  // 纳秒
    uint64_t tsc_target = tsc + us * 1000;  // 转换为纳秒

    // Check if we should sleep for a significant portion
    if (us > 100) {
        // Sleep for most of the time, then busy-wait for precision
        std::this_thread::sleep_for(std::chrono::microseconds(us * 9 / 10));
    }

    while ((tsc = arm64_cnt_vct()) < tsc_target) {
        std::this_thread::yield();
    }
}

inline void run_task(size_t type, size_t us)
{
    if (type == 0) {
        cpu_intensive_task(us);
    }
    if (type == 1) {
        io_intensive_task(us);
    }
    if (type == 2) {
        cpu_suspend_task(us);
    }
}

// mirror ffrt qos class
const qos_class_t dispatch_qos[] { QOS_CLASS_BACKGROUND, QOS_CLASS_UTILITY, QOS_CLASS_DEFAULT,
    QOS_CLASS_USER_INITIATED, QOS_CLASS_USER_INTERACTIVE, QOS_CLASS_USER_INTERACTIVE, QOS_CLASS_USER_INTERACTIVE };

class QoSGenerator {
public:
    QoSGenerator(qos_class_t qos = QOS_CLASS_UNSPECIFIED) : m_qos(qos)
    {
        if (m_qos == QOS_CLASS_UNSPECIFIED) {
            m_engine.seed(1234567);
        }
    }
    
    // force ffrt_qos convert
    QoSGenerator(uint64_t ffrt_qos, bool isFFRT)
    {
        (void)isFFRT;
        m_qos = dispatch_qos[ffrt_qos > 5 ? ffrt_qos : 5];
    }
    
    ~QoSGenerator() = default;
    
    operator qos_class_t()
    {
        if (m_qos == QOS_CLASS_UNSPECIFIED) {
            return dispatch_qos[m_dist(m_engine)];
        } else {
            return m_qos;
        }
    }
private:
    qos_class_t m_qos;
    std::mt19937 m_engine;
    std::uniform_int_distribution<int> m_dist {2, 5};
};

#endif /* util_h */
